// #ifndef FILE_H
// #define FILE_H
// #include <string>
// #include <fstream>
// using namespace std;
// class File
// {
// public:
//     File()
//     {
//         size = 0;
//         capacity = 16;
//         rows = new string[capacity];
//         charCount = 0;
//     }
//     File(const File &other)
//     {
//         size = 0;
//         capacity = 16;
//         rows = new string[capacity];
//         charCount = 0;
//         name = other.name;
//         for (int i = 0; i < other.getRowCount(); i++)
//             insertRow(other.get(i), i);
//     }
//     File(const string &name) : name(name)
//     {
//         size = 0;
//         capacity = 16;
//         rows = new string[capacity];
//         charCount = 0;
//     }
//     bool open()
//     {
//         ifstream infile(name);
//         if (infile.is_open())
//         {
//             string line;
//             int i = 0;
//             while (getline(infile, line))
//                 insertRow(line, i++);
//             infile.close();
//         }
//         else
//         {
//             ofstream outfile(name);
//             outfile.close();
//         }
//         if (empty())
//             insertRow("", 0);
//         return true;
//     }
//     bool insertRow(const string &s, int row)
//     {
//         if (row < 0 || row > size)
//             return false;
//         if (size == capacity)
//             resize(capacity * 2);
//         for (int i = size; i > row; i--)
//             rows[i] = rows[i - 1];
//         rows[row] = s;
//         size++;
//         charCount += s.size();
//         return true;
//     }
//     bool insertChar(char ch, int row, int pos)
//     {
//         if (row < 0 || row > size)
//             return false;
//         if (pos < 0 || pos > (int)rows[row].size())
//             return false;
//         rows[row].insert(pos, 1, ch);
//         charCount++;
//         return true;
//     }
//     bool eraseRow(int row)
//     {
//         if (row < 0 || row >= size)
//             return false;
//         charCount -= (int)rows[row].size();
//         for (int i = row; i < size - 1; i++)
//             rows[i] = rows[i + 1];
//         size--;
//         return true;
//     }
//     bool eraseChar(int row, int pos)
//     {
//         if (row < 0 || row >= size)
//             return false;
//         if (pos < 0 || pos >= (int)rows[row].size())
//             return false;
//         charCount--;
//         rows[row].erase(pos, 1);
//         return true;
//     }
//     bool enter(int row, int pos)
//     {
//         if (row < 0 || row >= size)
//             return false;
//         if (pos < 0 || pos > (int)rows[row].size())
//             return false;
//         string str = rows[row];
//         rows[row] = str.substr(0, pos);
//         insertRow(str.substr(pos), row + 1);
//         charCount -= (int)str.substr(pos).size();
//         return true;
//     }
//     bool backUp(int row)
//     {
//         if (row <= 0 || row >= size)
//             return false;
//         charCount += (int)rows[row].size();
//         rows[row - 1].append(rows[row]);
//         return eraseRow(row);
//     }
//     bool empty() const
//     {
//         return size == 0;
//     }
//     void replace(const string &target, const string &replacement)
//     {
//         charCount = 0;
//         for (int i = 0; i < size; i++)
//         {
//             size_t pos = 0;
//             string &s = rows[i];
//             while ((pos = s.find(target, pos)) != string::npos)
//             {
//                 s.replace(pos, target.size(), replacement);
//                 pos += replacement.size();
//             }
//             charCount += s.size();
//         }
//     }
//     string get(int row) const
//     {
//         if (row < 0 || row >= size)
//             return "";
//         return rows[row];
//     }
//     string getName() const
//     {
//         return name;
//     }
//     bool setRow(int row, const string &str)
//     {
//         if (row < 0 || row > size)
//             return false;
//         rows[row] = str;
//         return true;
//     }
//     int getRowCount() const
//     {
//         return size;
//     }
//     long getCharCount() const
//     {
//         return charCount;
//     }

// private:
//     void resize(int newCapacity)
//     {
//         capacity = newCapacity;
//         string *newRows = new string[capacity];
//         for (int i = 0; i < size; i++)
//             newRows[i] = rows[i];
//         delete[] rows;
//         rows = newRows;
//     }
//     string name;
//     int size;
//     int capacity;
//     string *rows;
//     long charCount;
// };

// #endif

#ifndef FILE_H
#define FILE_H
#include <list>
#include <vector>
#include <string>
#include <fstream>
#include <iterator>
#include <ncurses.h>
using namespace std;
class File
{
public:
    File()
    {
        rowCount = 0;
        charCount = 0;
        blockSize = 100;
    }
    File(const File &other)
    {
        rowCount = 0;
        charCount = 0;
        blockSize = 100;
        name = other.name;
        for (int i = 0; i < other.getRowCount(); i++)
            insertRow(other.get(i), i);
    }
    File(const string &name) : name(name)
    {
        rowCount = 0;
        charCount = 0;
        blockSize = 100;
    }
    bool open()
    {
        ifstream infile(name);
        if (infile.is_open())
        {
            string line;
            int i = 0;
            while (getline(infile, line))
                insertRow(line, i++);
            infile.close();
        }
        else
        {
            ofstream outfile(name);
            outfile.close();
        }
        if (empty())
            insertRow("", 0);
        return true;
    }
    void insertRow(const string &s, int row)
    {
        int idx = row / blockSize;
        while ((int)blocks.size() <= idx)
        {
            blocks.push_back(list<string>());
        }

        auto it = getIt(row, idx);
        blocks[idx].insert(it, s);
        moveBackward(idx);
        rowCount++;
        charCount += s.size();
    }
    void insertChar(char ch, int row, int pos)
    {
        int idx = row / blockSize;
        auto it = getIt(row, idx);
        it->insert(pos, 1, ch);
        charCount++;
    }
    void eraseRow(int row)
    {
        int idx = row / blockSize;
        auto it = getIt(row, idx);
        charCount -= (int)it->size();
        rowCount--;
        blocks[idx].erase(it);
        moveForward(idx);
    }
    void eraseChar(int row, int pos)
    {
        int idx = row / blockSize;
        auto it = getIt(row, idx);
        it->erase(pos, 1);
        charCount--;
    }
    void enter(int row, int pos)
    {
        int idx = row / blockSize;
        auto it = getIt(row, idx);
        string str = *it;
        *it = str.substr(0, pos);
        charCount -= (str.size() - pos);
        insertRow(str.substr(pos), row + 1);
    }
    void backUp(int row)
    {
        int idx1 = row / blockSize;
        auto it1 = getIt(row, idx1);
        int idx2 = (row - 1) / blockSize;
        auto it2 = getIt(row - 1, idx2);
        it2->append(*it1);
        charCount += it1->size();
        eraseRow(row);
    }
    void updateOverLengthRow(int row, int width)
    {
        auto it = getIt(row, row / blockSize);
        while ((int)it->size() > width)
        {
            if (row == rowCount - 1)
                insertRow("", row + 1);
            auto next = getIt(row + 1, (row + 1) / blockSize);
            next->insert(0, it->substr(width));
            it->erase(width);
            it = next;
            row++;
        }
    }
    bool empty() const
    {
        return rowCount == 0;
    }
    void replace(const string &target, const string &replacement)
    {
        charCount = 0;
        for (int i = 0; i < rowCount; i++)
        {
            auto it = getIt(i, i / blockSize);
            size_t pos = 0;
            while ((pos = it->find(target, pos)) != std::string::npos)
            {
                it->replace(pos, target.length(), replacement);
                pos += replacement.length();
            }
            charCount += (int)it->size();
        }
    }
    string get(int row) const
    {
        int idx = row / blockSize;
        auto it = next(blocks[idx].begin(), row % blockSize);
        return *it;
    }
    string getName() const
    {
        return name;
    }
    void setRow(int row, const string &str)
    {
        int idx = row / blockSize;
        auto it = blocks[idx].begin();
        advance(it, row % blockSize);
        charCount -= (int)it->size();
        *it = str;
        charCount += (int)it->size();
    }
    int getRowCount() const
    {
        return rowCount;
    }
    long getCharCount() const
    {
        return charCount;
    }

private:
    void moveBackward(int idx)
    {
        while ((int)blocks[idx].size() > blockSize)
        {
            if (idx == (int)blocks.size() - 1)
                blocks.push_back(list<string>());
            blocks[idx + 1].push_front(blocks[idx].back());
            blocks[idx].pop_back();
            idx++;
        }
    }
    void moveForward(int idx)
    {
        while (idx + 1 < (int)blocks.size() && !blocks[idx + 1].empty())
        {
            blocks[idx].push_back(blocks[idx + 1].front());
            blocks[idx + 1].pop_front();
            idx++;
        }
    }
    list<string>::iterator getIt(int row, int idx)
    {
        auto it = blocks[idx].begin();
        advance(it, row % blockSize);
        return it;
    }
    int blockSize;
    string name;
    int rowCount;
    long charCount;
    vector<list<string>> blocks;
};

#endif